package com.hqyj.javaSpringBoot.modules.test.service.impl;

import com.hqyj.javaSpringBoot.modules.common.entity.Result;
import com.hqyj.javaSpringBoot.modules.common.entity.SearchBean;
import com.hqyj.javaSpringBoot.modules.test.dao.StudentRepository;
import com.hqyj.javaSpringBoot.modules.test.entity.Student;
import com.hqyj.javaSpringBoot.modules.test.service.StudentService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

@Service
public class StudentServiceImpl implements StudentService {
    @Autowired
    private StudentRepository studentRepository;
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    @Transactional
    public Result<Student> editStudent(Student student) {
//        studentRepository.saveAndFlush(student);
        studentRepository.insertStudent(student);
        return new Result<Student>(Result.ResultCode.success.code,
                "edit success.",student);
    }

    @Override
    @Transactional
    public Result<Object> deleteStudentById(int id) {
        studentRepository.deleteById(id);
        return new Result<Object>(Result.ResultCode.success.code,
                "delete success.");
    }

    @Override
    public Student getStudentById(int id) {
//        return studentRepository.getById(id);
//        return studentRepository.fin
//        return studentRepository.getStudentById(id);
        return studentRepository.getStudentByIdForSql(id);
    }

    @Override
    public List<Student> getStudents() {
        return Optional.ofNullable(studentRepository.findAll())
                .orElse(Collections.emptyList());
    }

    @Override
    public Student getStudentByNameAndEmail(String name, String email) {
        return studentRepository.findFirstByNameAndEmail(name,email);
    }

    @Override
    public Page<Student> getStudentsBySearchBean(SearchBean searchBean) {
        searchBean.initSearchBean();
//        return getStudentByExample(searchBean);
        return getStudentBySpecification(searchBean);
    }

    @Override
    @Transactional
    public Result<Object> insertStudents(List<Student> students) {
        students.stream().forEach(item->{
            entityManager.persist(item);
        });
        entityManager.flush();
        entityManager.clear();
        return new Result<Object>(Result.ResultCode.success.code,
                "insert success.");
    }

    private Page<Student> getStudentByExample(SearchBean searchBean){
        //          <S extends T> Page<S> findAll(Example<S> var1, Pageable var2);
        Sort.Direction direction= StringUtils.isBlank(searchBean.getDirection())||
                searchBean.getDirection().toLowerCase().equals("asc")?
                Sort.Direction.ASC:Sort.Direction.DESC;
        Sort sort=Sort.by(direction,searchBean.getOrderBy());
        Pageable pageable= PageRequest.of(searchBean.getCurrentPage()-1,searchBean.getPageSize(),sort);

        Student student=new Student();
        student.setName(searchBean.getKeyWord());
        student.setEmail(searchBean.getKeyWord());
        ExampleMatcher matcher=ExampleMatcher
                .matchingAny()
                .withMatcher("name",match->match.contains())
                .withMatcher("email",match->match.contains());
        Example<Student> example=Example.of(student,matcher);

        return studentRepository.findAll(example,pageable);
    }
    private Page<Student> getStudentBySpecification(SearchBean searchBean){
        Sort.Direction direction= StringUtils.isBlank(searchBean.getDirection())||
                searchBean.getDirection().toLowerCase().equals("asc")?
                Sort.Direction.ASC:Sort.Direction.DESC;
        Sort sort=Sort.by(direction,searchBean.getOrderBy());
        Pageable pageable= PageRequest.of(searchBean.getCurrentPage()-1,
                searchBean.getPageSize(),
                sort);

        Specification<Student> specification=new Specification<Student>() {
            /**
             * select* from test_student where create_date>? and
             * (id between 1 and 10 or name like '%?%')
             * order by ?? limit ?
             * @param root
             * @param criteriaQuery
             * @param criteriaBuilder
             * @return
             */
            @Override
            public Predicate toPredicate(Root<Student> root,
                                         CriteriaQuery<?> criteriaQuery,
                                         CriteriaBuilder criteriaBuilder) {
              return criteriaBuilder.and(
                        criteriaBuilder.greaterThan(
                                root.get("creatDate").as(LocalDateTime.class),
                                LocalDateTime.of(2021,8,20,0,0)
                        ),
                        criteriaBuilder.or(
                                criteriaBuilder.between(root.get("id"),1,11),
                                criteriaBuilder.like(
                                        root.get("name").as(String.class),
//                                        searchBean.getKeyWord()
                                        String.format("%%%s%%",searchBean.getKeyWord())
                                )
                        )
                );

            }
        };

        return studentRepository.findAll(specification,pageable);
    }


}
